var log = require('../config/log4jsConfig');
var path = require('path');
var util = require('util');
var fs = require('fs');
var Client = require('fabric-client');
var User = require('fabric-client/lib/User.js');
var FabricCAService = require('fabric-ca-client');
var config = require('../config/baseConfig');
var URL = require('url');

// 组织关系/地址/证书描述文件
var ORGS;

function init() {
  if (!ORGS) {
    Client.addConfigFile(path.join(config.NETWORK_CONFIG_PATH, config.NETWORK_CONFIG_NAME));
    ORGS = Client.getConfigSetting('network-config');
  }
}

var createChannel = async function (channelName, ordererOrg, ordererId) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  // 创建通道需要使用Admin身份
  log.info('Use local login authentication .');
  let admin_key = ORGS.peer[config.ORG]['admin']['keyPath'];
  let admin_sert = ORGS.peer[config.ORG]['admin']['certPath'];
  let mspid = ORGS.peer[config.ORG]['mspid'];
  await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  var envelope = fs.readFileSync(path.join(config.CHANNEL_TX_PATH, config.CHANNEL_TX_NAME));
  var channelConfig = client.extractChannelConfig(envelope);
  var signature = client.signChannelConfig(channelConfig);
  // 构建request对象
  var txId = client.newTransactionID();
  var request = {
    name: 'mychannel',
    orderer: orderer,
    config: channelConfig,
    signatures: [signature],
    txId: txId
  };
  return client.createChannel(request);
}
exports.createChannel = createChannel;

var joinChannel = async function (org, peerid, ordererOrg, ordererId, channelName) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);

  // 需要使用Admin身份
  log.info('Use local login authentication .');
  let admin_key = ORGS.peer[org]['admin']['keyPath'];
  let admin_sert = ORGS.peer[org]['admin']['certPath'];
  let mspid = ORGS.peer[org]['mspid'];
  await getOrgUser4Local(client, admin_key, admin_sert, mspid);

  let targets = [];

  return channel.getGenesisBlock({txId: client.newTransactionID()}).then((block) => {
    genesis_block = block;
    targets.push(peer);
    var request = {
      targets: targets,
      txId: client.newTransactionID(),
      block: genesis_block
    };
    return channel.joinChannel(request, 30000);
  }, (err) => {
    throw new Error('Failed to enroll user \'admin\' due to error: ' + err.stack ? err.stack : err);
  }).then((results) => {
    log.debug(util.format('Join Channel RESPONSE : %j', results));
    if (results && results[0] && results[0].response && results[0].response.status == 200) {
      return {"status": "SUCCESS"};
    } else {
      throw new Error('Failed to join channel');
    }
  }, (err) => {
    throw new Error('Failed to join channel due to error: ' + err.stack ? err.stack : err);
  });
}
exports.joinChannel = joinChannel;

var installChaincode = async function (org, peerid, ordererOrg, ordererId, chaincodePath, chaincodeVersion, chaincodeId, channelName) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);

  // 需要使用Admin身份
  log.info('Use local login authentication .');
  let admin_key = ORGS.peer[org]['admin']['keyPath'];
  let admin_sert = ORGS.peer[org]['admin']['certPath'];
  let mspid = ORGS.peer[org]['mspid'];
  await getOrgUser4Local(client, admin_key, admin_sert, mspid);

  let targets = [peer];
  let chaincode_path = chaincodePath;
  let cc_id = chaincodeId;
  let language = config.CHAINCODE_TYPE;
  let version = chaincodeVersion;
  let request = {
    targets: targets,
    chaincodePath: chaincode_path,
    chaincodeId: cc_id,
    chaincodeType: language,
    chaincodeVersion: version
  };
  log.debug(util.format('The install request is %j', request));
  return client.installChaincode(request).then((results) => {
      var proposalResponses = results[0];
      var proposal = results[1];
      var all_good = true;
      var errors = [];
      for (var i in proposalResponses) {
        let one_good = false;
        if (proposalResponses && proposalResponses[i].response && proposalResponses[i].response.status === 200) {
          one_good = true;
          log.info('install proposal was good');
        } else {
          log.error('install proposal was bad');
          errors.push(proposalResponses[i]);
        }
        all_good = all_good & one_good;
      }
      if (all_good) {
        log.info('Successfully sent install Proposal and received ProposalResponse: Status - %s', proposalResponses[0].response.status);
        return proposalResponses[0].response.status;
      } else {
        throw new Error(util.format('Failed to send install Proposal or receive valid response: %s', errors));
      }
    },
    (err) => {
      throw new Error('Failed to send install proposal due to error: ' + err.stack ? err.stack : err);
    });

}
exports.installChaincode = installChaincode;

var instantiateChaincode = async function (org, peerid, ordererOrg, ordererId, chaincodePath, chaincodeVersion, chaincodeId, channelName, parameter, upgrade) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);

  // 需要使用Admin身份
  log.info('Use local login authentication .');
  let admin_key = ORGS.peer[org]['admin']['keyPath'];
  let admin_sert = ORGS.peer[org]['admin']['certPath'];
  let mspid = ORGS.peer[org]['mspid'];
  await getOrgUser4Local(client, admin_key, admin_sert, mspid);

  let eventhubs = [];
  let eh = await geteventhub(client, org, peerid);
  eh.connect();
  eventhubs.push(eh);
  var txId = null;
  return channel.initialize().then(() => {

    txId = client.newTransactionID();
    let chaincode_path = chaincodePath;
    let cc_id = chaincodeId;
    let language = config.CHAINCODE_TYPE;
    let version = chaincodeVersion;
    let args = parameter;

    // TODO 可以设置背书规则，暂时不用
    // var policy = {
    //   identities: [
    //     {role: {name: 'member', mspId: 'Org1MSP'}},
    //     {role: {name: 'member', mspId: 'Org2MSP'}},
    //     {role: {name: 'admin', mspId: 'Org1MSP'}},
    //     {role: {name: 'admin', mspId: 'Org2MSP'}}
    //   ],
    //   policy: {
    //     '1-of': [
    //       {'1-of': [{'signed-by': 0}, {'signed-by': 2}]},
    //       {'1-of': [{'signed-by': 1}, {'signed-by': 3}]}
    //     ]
    //   }
    // };

    var request = {
      chaincodeType: language,
      chaincodePath: chaincode_path,
      chaincodeId: cc_id,
      chaincodeVersion: version,
      fcn: 'init',
      args: args,
      txId: txId
    };

    // 增加更新链码的操作
    if (upgrade == 'upgrade') {
      return channel.sendUpgradeProposal(request, 10 * 60 * 1000);
    } else {
      return channel.sendInstantiateProposal(request, 10 * 60 * 1000);
    }
  }).then((results) => {
    var proposalResponses = results[0];
    var proposal = results[1];
    var all_good = true;
    var errors = [];
    for (var i in proposalResponses) {
      let one_good = false;
      if (proposalResponses && proposalResponses[i].response && proposalResponses[i].response.status === 200) {
        one_good = true;
        log.info('instantiate proposal was good');
      } else {
        log.error('instantiate proposal was bad');
        errors.push(proposalResponses[i]);
      }
      all_good = all_good & one_good;
    }
    if (all_good) {
      log.info('Successfully sent instantiate Proposal and received ProposalResponse: Status - %s', proposalResponses[0].response.status);
      var request = {
        proposalResponses: proposalResponses,
        proposal: proposal
      };
      var deployId = txId.getTransactionID();
      var eventPromises = [];
      eventhubs.forEach((eh) => {
        let txPromise = new Promise((resolve, reject) => {
          let handle = setTimeout(reject, 300000);
          eh.registerTxEvent(deployId.toString(), (tx, code) => {
            log.debug('The chaincode instantiate transaction has been committed on peer ' + eh.getPeerAddr());
            clearTimeout(handle);
            eh.unregisterTxEvent(deployId);
            if (code !== 'VALID') {
              log.error('The chaincode instantiate transaction was invalid, code = ' + code);
              reject();
            } else {
              log.info('The chaincode instantiate transaction was valid.');
              resolve();
            }
          }, (err) => {
            log.error('There was a problem with the instantiate event ' + err);
            clearTimeout(handle);
            eh.unregisterTxEvent(deployId);
          });
        });
        log.debug('register eventhub %s with tx=%s', eh.getPeerAddr(), deployId);
        eventPromises.push(txPromise);
      });
      var sendPromise = channel.sendTransaction(request);
      return Promise.all([sendPromise].concat(eventPromises))
        .then((results) => {
          log.debug('Event promise all complete and testing complete');
          return results[0];
        }).catch((err) => {
          throw new Error('Failed to send instantiate transaction and get notifications within the timeout period.');
        });
    } else {
      throw new Error(util.format('Failed to send instantiate Proposal or receive valid response: %s', errors));
    }
  }, (err) => {
    throw new Error('Failed to send instantiate proposal due to error: ' + err.stack ? err.stack : err);
  })
}
exports.instantiateChaincode = instantiateChaincode;

var queryCc = async function (org, peerid, ordererOrg, ordererId, chaincodeVersion, fcn, parameter, chaincodeId, channelName) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);

  if (config.CA_CLIENT_ENABLE) {
    log.info('Use CA login authentication .');
    await getOrgUser4FabricCa(client, 'admin', 'adminpw', config.ORG, config.PEER);
  } else {
    log.info('Use local login authentication .');
    let admin_key = ORGS.peer[org]['admin']['keyPath'];
    let admin_sert = ORGS.peer[org]['admin']['certPath'];
    let mspid = ORGS.peer[org]['mspid'];
    await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  }

  // return channel.initialize().then(() => {
  let targets = [peer];
  var tx_id = client.newTransactionID();
  let cc_id = chaincodeId;
  let args = parameter;
  let func = fcn;
  var request = {
    chaincodeId: cc_id,
    txId: tx_id,
    targets: targets,
    fcn: func,
    args: args
  };
  return channel.queryByChaincode(request).then((sendtransresult) => {
    if (sendtransresult) {
      for (let i = 0; i < sendtransresult.length; i++) {
        // 结果转换成utf-8
        return sendtransresult[i].toString('utf8');
      }
    } else {
      Promise.reject(new Error('Failed to get response on query'));
    }
  }, (err) => {
    log.error('Error stack : \n %s', err.stack);
  })
  // })
}
exports.queryCc = queryCc;

var sendTransaction = async function (org, peerid, ordererOrg, ordererId, chaincodeVersion, chaincodeId, channelName, fcn, parameter) {
  init();
  var pass_results = null;
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);
  
  if (config.CA_CLIENT_ENABLE) {
    log.info('Use CA login authentication .');
    await getOrgUser4FabricCa(client, 'admin', 'adminpw', config.ORG, config.PEER);
  } else {
    log.info('Use local login authentication .');
    let admin_key = ORGS.peer[org]['admin']['keyPath'];
    let admin_sert = ORGS.peer[org]['admin']['certPath'];
    let mspid = ORGS.peer[org]['mspid'];
    await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  }

  // TODO 此处设置eventhub 用来监听transation 是否成功
  let eventhubs = [];
  let eh = await geteventhub(client, org, peerid);
  eh.connect();
  eventhubs.push(eh);

  return channel.initialize().then(() => {

    var tx_id = client.newTransactionID();
    let cc_id = chaincodeId;
    let args = parameter;
    let func = fcn;
    var request = {
      chaincodeId: cc_id,
      fcn: func,
      args: args,
      chainId: cc_id,
      txId: tx_id
    };
    return channel.sendTransactionProposal(request).then((results) => {
      pass_results = results;
      var sleep_time = 0;
      if (process.argv.length > 2) {
        if (process.argv[2].indexOf('sleep=') === 0) {
          sleep_time = process.argv[2].split('=')[1];
        }
      }
      log.info('*****************************************************************************');
      log.info('stop and start the peer event hub ---- N  O  W ----- you have ' + sleep_time + ' millis ' + (new Date()).toString());
      log.info('*****************************************************************************');
      return sleep(sleep_time);
    }).then(() => {
      var proposalResponses = pass_results[0];
      var proposal = pass_results[1];
      var header = pass_results[2];
      var all_good = true;
      for (var i in proposalResponses) {
        let one_good = false;
        if (proposalResponses && proposalResponses[0].response &&
          proposalResponses[0].response.status === 200) {
          one_good = true;
          log.info('transaction proposal was good');
        } else {
          log.error('transaction proposal was bad');
        }
        all_good = all_good & one_good;
      }
      if (all_good) {
        log.info(util.format(
          'Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s", metadata - "%s", endorsement signature: %s',
          proposalResponses[0].response.status, proposalResponses[0].response.message,
          proposalResponses[0].response.payload, proposalResponses[0].endorsement
            .signature));

        var request = {
          proposalResponses: proposalResponses,
          proposal: proposal,
          header: header
        };

        // TODO 需要注册 eventHub
        // 没有注册并不能知道orderer节点是否通过了此处的交易请求，并且peer为此背书
        // 因此在并发情况下，不能保证每笔交易都是成功的
        var deployId = tx_id.getTransactionID();
        var eventPromises = [];
        eventhubs.forEach((eh) => {
          let txPromise = new Promise((resolve, reject) => {
            let handle = setTimeout(reject, 30000);
            eh.registerTxEvent(deployId.toString(),
              (tx, code) => {
                clearTimeout(handle);
                eh.unregisterTxEvent(deployId);
                if (code !== 'VALID') {
                  log.error('The balance transfer transaction was invalid, code = ' + code);
                  reject();
                } else {
                  log.info('The balance transfer transaction has been committed on peer ' + eh.getPeerAddr());
                  resolve();
                }
              },
              (err) => {
                clearTimeout(handle);
                log.info('Successfully received notification of the event call back being cancelled for ' + deployId);
                resolve();
              }
            );
          });
          eventPromises.push(txPromise);
        });

        var sendPromise = channel.sendTransaction(request);
        return Promise.all([sendPromise].concat(eventPromises)).then((results) => {
          log.debug(' event promise all complete and testing complete');
          return results[0];
        }).catch((err) => {
          log.error('Failed to send transaction and get notifications within the timeout period.');
          throw new Error('Failed to send transaction and get notifications within the timeout period.');
        });
      } else {
        log.error('Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...');
        throw new Error('Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...');
      }
    }, (err) => {
      log.error('Error stack : \n %s', err.stack);
      return '{"status":"ERROR"}';
    }).then((response) => {

      if (response.status === 'SUCCESS') {
        log.info('Successfully sent transaction to the orderer.');
        log.info('******************************************************************');
        log.info('export E2E_TX_ID=' + '\'' + tx_id.getTransactionID() + '\'');
        log.info('******************************************************************');
        log.debug('invokeChaincode end');
        channel.close();
        log.info('Successfully closed all connections');
        return response;
      } else {
        log.error('Failed to order the transaction. Error code: ' + response.status);
        throw new Error('Failed to order the transaction. Error code: ' + response.status);
      }
    }, (err) => {
      log.error('Failed to send transaction due to error: ' + err.stack ? err.stack : err);
      throw new Error('Failed to send transaction due to error: ' + err.stack ? err.stack : err);
    });
  })
}
exports.sendTransaction = sendTransaction;

var noEventHubSendTransaction = async function (org, peerid, ordererOrg, ordererId, chaincodeVersion, chaincodeId, channelName, fcn, parameter) {
  init();
  var pass_results = null;
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);

  if (config.CA_CLIENT_ENABLE) {
    log.info('Use CA login authentication .');
    await getOrgUser4FabricCa(client, 'admin', 'adminpw', config.ORG, config.PEER);
  } else {
    log.info('Use local login authentication .');
    let admin_key = ORGS.peer[org]['admin']['keyPath'];
    let admin_sert = ORGS.peer[org]['admin']['certPath'];
    let mspid = ORGS.peer[org]['mspid'];
    await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  }

  var tx_id = client.newTransactionID();
  let cc_id = chaincodeId;
  let args = parameter;
  let func = fcn;
  let request = {
    chaincodeId: cc_id,
    fcn: func,
    args: args,
    chainId: cc_id,
    txId: tx_id
  };
  return channel.sendTransactionProposal(request).then((chaincodeinvokresult) => {
    var proposalResponses = chaincodeinvokresult[0];
    var proposal = chaincodeinvokresult[1];
    var header = chaincodeinvokresult[2];
    var all_good = true;
    for (var i in proposalResponses) {
      let one_good = false;
      if (proposalResponses && proposalResponses[0].response &&
        proposalResponses[0].response.status === 200) {
        one_good = true;
        log.info('transaction proposal was good');
      } else {
        log.error('transaction proposal was bad');
      }
      all_good = all_good & one_good;
    }
    if (all_good) {
      log.info(util.format(
        'Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s", metadata - "%s", endorsement signature: %s',
        proposalResponses[0].response.status, proposalResponses[0].response.message,
        proposalResponses[0].response.payload, proposalResponses[0].endorsement
          .signature));

      var request = {
        proposalResponses: proposalResponses,
        proposal: proposal,
        header: header
      };

      return channel.sendTransaction(request);
    }
  }, (err) => {
    log.error('Failed to send transaction due to error: ' + err.stack ? err.stack : err);
    throw new Error('Failed to send transaction due to error: ' + err.stack ? err.stack : err);
  }).then((response) => {
    return response;
  }, (err) => {
    log.error('Failed to send transaction due to error: ' + err.stack ? err.stack : err);
    throw new Error('Failed to send transaction due to error: ' + err.stack ? err.stack : err);
  });
}
exports.noEventHubSendTransaction = noEventHubSendTransaction;

var getBlockChainInfo = async function (channelName, org, peerid, ordererOrg, ordererId) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);

  if (config.CA_CLIENT_ENABLE) {
    log.info('Use CA login authentication .');
    await getOrgUser4FabricCa(client, 'admin', 'adminpw', config.ORG, config.PEER);
  } else {
    log.info('Use local login authentication .');
    let admin_key = ORGS.peer[org]['admin']['keyPath'];
    let admin_sert = ORGS.peer[org]['admin']['certPath'];
    let mspid = ORGS.peer[org]['mspid'];
    await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  }
  return channel.queryInfo(peer);
}
exports.getBlockChainInfo = getBlockChainInfo;

var getblockInfobyNum = async function (channelName, org, peerid, ordererOrg, ordererId, blockNumber) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);

  if (config.CA_CLIENT_ENABLE) {
    log.info('Use CA login authentication .');
    await getOrgUser4FabricCa(client, 'admin', 'adminpw', config.ORG, config.PEER);
  } else {
    log.info('Use local login authentication .');
    let admin_key = ORGS.peer[org]['admin']['keyPath'];
    let admin_sert = ORGS.peer[org]['admin']['certPath'];
    let mspid = ORGS.peer[org]['mspid'];
    await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  }
  return channel.queryBlock(blockNumber, peer, null);
}
exports.getblockInfobyNum = getblockInfobyNum;

var getblockInfobyHash = async function (channelName, org, peerid, ordererOrg, ordererId, blockHash) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);

  if (config.CA_CLIENT_ENABLE) {
    log.info('Use CA login authentication .');
    await getOrgUser4FabricCa(client, 'admin', 'adminpw', config.ORG, config.PEER);
  } else {
    log.info('Use local login authentication .');
    let admin_key = ORGS.peer[org]['admin']['keyPath'];
    let admin_sert = ORGS.peer[org]['admin']['certPath'];
    let mspid = ORGS.peer[org]['mspid'];
    await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  }
  return channel.queryBlockByHash(new Buffer(blockHash, "hex"), peer);
}
exports.getblockInfobyHash = getblockInfobyHash;

var getblockInfobyTxId = async function (channelName, org, peerid, ordererOrg, ordererId, tx_id) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);

  if (config.CA_CLIENT_ENABLE) {
    log.info('Use CA login authentication .');
    await getOrgUser4FabricCa(client, 'admin', 'adminpw', config.ORG, config.PEER);
  } else {
    log.info('Use local login authentication .');
    let admin_key = ORGS.peer[org]['admin']['keyPath'];
    let admin_sert = ORGS.peer[org]['admin']['certPath'];
    let mspid = ORGS.peer[org]['mspid'];
    await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  }
  return channel.queryTransaction(tx_id, peer)
}
exports.getblockInfobyTxId = getblockInfobyTxId;

var getPeerChannel = async function (channelName, org, peerid, ordererOrg, ordererId) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);

  if (config.CA_CLIENT_ENABLE) {
    log.info('Use CA login authentication .');
    await getOrgUser4FabricCa(client, 'admin', 'adminpw', config.ORG, config.PEER);
  } else {
    log.info('Use local login authentication .');
    let admin_key = ORGS.peer[org]['admin']['keyPath'];
    let admin_sert = ORGS.peer[org]['admin']['certPath'];
    let mspid = ORGS.peer[org]['mspid'];
    await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  }

  return client.queryChannels(peer);
}
exports.getPeerChannel = getPeerChannel;

var getPeerInstallCc = async function (channelName, org, peerid, ordererOrg, ordererId) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);
  // 需要使用Admin身份
  log.info('Use local login authentication .');
  let admin_key = ORGS.peer[org]['admin']['keyPath'];
  let admin_sert = ORGS.peer[org]['admin']['certPath'];
  let mspid = ORGS.peer[org]['mspid'];
  await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  return client.queryInstalledChaincodes(peer);
}
exports.getPeerInstallCc = getPeerInstallCc;

var getPeerInstantiatedCc = async function (channelName, org, peerid, ordererOrg, ordererId) {
  init();
  let client = new Client();
  let channel = client.newChannel(channelName);
  let orderer = await getorderer(client, ordererOrg, ordererId);
  channel.addOrderer(orderer);
  let peer = await getpeer(client, org, peerid);
  channel.addPeer(peer);
  // 需要使用Admin身份
  log.info('Use local login authentication .');
  let admin_key = ORGS.peer[org]['admin']['keyPath'];
  let admin_sert = ORGS.peer[org]['admin']['certPath'];
  let mspid = ORGS.peer[org]['mspid'];
  await getOrgUser4Local(client, admin_key, admin_sert, mspid);
  return channel.queryInstantiatedChaincodes(peer);
}
exports.getPeerInstantiatedCc = getPeerInstantiatedCc;

var keyPEM = null;
var certPEM = null;

async function getOrgUser4Local(client, admin_key, admin_sert, mspid) {
  if (!keyPEM || !certPEM) {
    log.info('>>>> Static parameters keyPEM and certPEM . <<<<');
    let keyPath = path.join(__dirname, admin_key);
    keyPEM = Buffer.from(readAllFiles(keyPath)[0]).toString();
    let certPath = path.join(__dirname, admin_sert);
    certPEM = readAllFiles(certPath)[0].toString();
  }
  var tempdir = "./fabric-client-kvs";
  return Client.newDefaultKeyValueStore({
    path: tempdir
  }).then((store) => {
    client.setStateStore(store);
    return client.createUser({
      username: 'Admin',
      mspid: mspid,
      cryptoContent: {
        privateKeyPEM: keyPEM,
        signedCertPEM: certPEM
      }
    });
  });
}

async function getOrgUser4FabricCa(client, username, password, org, peerid) {
  var tempdir = "./fabric-client-kvs";
  var member = new User(username);
  var cryptoSuite = member.getCryptoSuite();
  if (!cryptoSuite) {
    cryptoSuite = Client.newCryptoSuite();
    // if (org) {
    //   cryptoSuite.setCryptoKeyStore(Client.newCryptoKeyStore({path: tempdir + "/" + org + "/" + username}));
    // }
  }
  client.setCryptoSuite(cryptoSuite);
  let caClient = null;
  let urlStr = ORGS.peer[org].ca.url;
  let url = URL.parse(urlStr);
  let protocol = url.protocol;
  let host = url.host;
  let caName = ORGS.peer[org].ca.name;
  let msp = ORGS.peer[org].mspid;
  log.debug('The ca url.protocol is %s , url.host is %s ', protocol, host);
  if (protocol == 'http:') {
    log.debug('Use http protocol');
    caClient = new FabricCAService(urlStr, null, caName, cryptoSuite);
  } else if (protocol == 'https:') {
    log.debug('Use https protocol');
    let tlsOptions = {
      trustedRoots: [],
      verify: false
    };
    caClient = new FabricCAService(urlStr, null, caName, cryptoSuite);
  } else {
    log.error('You must give me a http type url address');
  }

  member.setCryptoSuite(cryptoSuite);
  return caClient.enroll({
    enrollmentID: username,
    enrollmentSecret: password
  }).then((enrollment) => {
    log.info('Successfully enrolled user  [' + username + ']');
    return member.setEnrollment(enrollment.key, enrollment.certificate, msp)
  }).then(() => {
    var skipPersistence = false;
    if (!client.getStateStore()) {
      skipPersistence = true;
    }
    return client.setUserContext(member, skipPersistence);
  }).catch((err) => {
    log.error('Enroll admin error :' + err.stack);
    throw new Error('Enroll admin error : ' + err.stack ? err.stack : err);
  });
}

function readAllFiles(dir) {
  var files = fs.readdirSync(dir);
  var certs = [];
  files.forEach((file_name) => {
    let file_path = path.join(dir, file_name);
    let data = fs.readFileSync(file_path);
    certs.push(data);
  });
  return certs;
}

var peertls = null;

async function getpeer(client, org, peerId) {
  let url = URL.parse(ORGS.peer[org][peerId].requests);
  let protocol = url.protocol;
  let host = url.host;
  let opt = {}
  opt['ssl-target-name-override'] = ORGS.peer[org][peerId]['server-hostname'];
  let peer;
  log.debug('The peer url.protocol is %s , url.host is %s ', protocol, host);
  if (protocol == 'grpc:') {
    log.debug('Use grpc protocol');
    peer = client.newPeer(url, opt);
  } else if (protocol == 'grpcs:') {
    log.debug('Use grpcs protocol');
    if (!peertls) {
      log.info('>>>> Static parameters peertls . <<<<');
      let data = fs.readFileSync(path.join(__dirname, ORGS.peer[org][peerId]['tls_cacerts']));
      peertls = Buffer.from(data).toString();
    }
    opt.pem = peertls;
    peer = client.newPeer(url, opt);
  } else {
    log.error('You must give me a grpc type url address')
  }
  return peer;
}

var orderertls = null;

async function getorderer(client, ordererOrg, ordererId) {
  let url = URL.parse(ORGS.orderer[ordererOrg][ordererId].url);
  let protocol = url.protocol;
  let host = url.host;
  let opt = {}
  opt['ssl-target-name-override'] = ORGS.orderer[ordererOrg][ordererId]['server-hostname'];
  let orderer;
  log.debug('The orderer url.protocol is %s , url.host is %s ', protocol, host);
  if (protocol == 'grpc:') {
    log.debug('Use grpc protocol');
    orderer = client.newOrderer(url, opt);
  } else if (protocol == 'grpcs:') {
    log.debug('Use grpcs protocol');
    if (!orderertls) {
      log.info('>>>> Static parameters orderertls . <<<<');
      let data = fs.readFileSync(path.join(__dirname, ORGS.orderer[ordererOrg][ordererId]['tls_cacerts']));
      orderertls = Buffer.from(data).toString();
    }
    opt.pem = orderertls;
    orderer = client.newOrderer(url, opt);
  } else {
    log.error('You must give me a grpc type url address')
  }
  return orderer;
}

var eventhubtls = null;

async function geteventhub(client, org, peerid) {
  let eh = client.newEventHub();
  let url = URL.parse(ORGS.peer[org][peerid].events);
  let protocol = url.protocol;
  let host = url.host;
  let opt = {}
  opt['ssl-target-name-override'] = ORGS.peer[org][peerid]['server-hostname'];
  log.debug('The peer eventhub url.protocol is %s , url.host is %s ', protocol, host);
  if (protocol == 'grpc:') {
    log.debug('Use grpc protocol');
  } else if (protocol == 'grpcs:') {
    log.debug('Use grpcs protocol');
    if (!eventhubtls) {
      log.info('>>>> Static parameters eventhubtls . <<<<');
      let data = fs.readFileSync(path.join(__dirname, ORGS.peer[org][peerid]['tls_cacerts']));
      eventhubtls = Buffer.from(data).toString();
    }
    opt.pem = eventhubtls;
  } else {
    log.error('You must give me a grpc type url address')
  }
  eh.setPeerAddr(url, opt);
  return eh;
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}